#pragma once

#include <string>
#include "Mutex.hpp"
#include<filesystem>
#include<fstream>
#include<ctime>
#include<memory>
#include<unistd.h>
#include<sstream>
namespace LogModule
{
    using namespace MutexModule;
    namespace fs=std::filesystem;
    #define gresp "\r\n"
    class LogStrategy
    {
        public:
        ~LogStrategy()=default;
        virtual void SyncLog(const std::string &message)=0;
    };
    class ConsoleLogStrategy:public LogStrategy
    {
        public:
        ConsoleLogStrategy()
        {

        }

        //将信息打印到控制台
        void SyncLog(const std::string&message)
        {
            LockGuard lockguard(_mutex);
            std::cout<<message<<std::endl;
        }
        ~ConsoleLogStrategy()
        {

        }
        private:
        Mutex _mutex;
    };

    const std::string defaultpath="./log";
    const std::string defaultfile="my.log";

    class FileLogStrategy:public LogStrategy
    {
        public:

        //根据默认设置的位置创建.log文件
        FileLogStrategy(const std::string& path=defaultpath,const std::string& file=defaultfile)
        :_path(path),_file(file)
        {
            LockGuard lockguard(mutex);
            if(fs::exists(_path))
            {
                return;
            }
            try{
                fs::create_directories(_path);
            }
            catch(const fs::filesystem_error&e){
                std::cerr<<e.what()<<std::endl;
            }
        }

        //将信息输出到对应的.log文件
        void SyncLog(const std::string& message)override
        {
            LockGuard lockguard(mutex);
            std::string filename=_path+(_path.back()=='/'?"":"/")+_file;
            std::ofstream out(filename,std::ios::app);
            if(!out.is_open())
            {
                return;
            }
            out<<message<<std::endl;
            out.close();  
        }
        ~FileLogStrategy()
        {}
        private:
        std::string _path;
        std::string _file;
        Mutex mutex;
    };

    //LogLevel枚举信息，使用的是class格式的
    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    //枚举枚举类型信息输出
    std::string Level2Str(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::WARNING:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
        }
    }

    //获取现在的时间信息
    std::string GetTimeStamp()
    {
        time_t timestring=time(nullptr);
        struct tm ts;
        localtime_r(&timestring,&ts);
        char timechar[128];
        snprintf(timechar,sizeof(timechar),"%4d-%02d-%02d %02d:%02d:%02d"
        ,ts.tm_year+1900
        ,ts.tm_mon
        ,ts.tm_mday
        ,ts.tm_hour
        ,ts.tm_min
        ,ts.tm_sec);
        return timechar;
    }

    class Logger
    {
        public:
        Logger()
        {
            EnableConsoleLogStrategy();
        }
        void EnableConsoleLogStrategy()
        {
            _fflush_strategy=std::make_unique<ConsoleLogStrategy>();
        }
        void EnableFileLogStrategy()
        {
            _fflush_strategy=std::make_unique<FileLogStrategy>();
        }
        class LogMessage
        {
            public:
            LogMessage(LogLevel&level,std::string& src_name,int line,Logger& logger)
            :_curr_time(GetTimeStamp()),
            _level(level),
            _src_name(src_name),
            _line_number(line),
            _pid(getpid()),
            _logger(logger)
            {
                std::stringstream ss;
                ss<<"["<<_curr_time<<"]"
                <<"["<<Level2Str(_level)<<"]"
                <<"["<<_pid<<"]"
                <<"["<<src_name<<"]"
                <<"["<<_line_number<<"]"
                <<"-";
                _loginfo=ss.str();
            }
            template<class T>
            LogMessage& operator<<(const T& msg)
            {
                std::stringstream ss;
                ss<<msg;
                _loginfo+=ss.str();
                return *this;
            }
            ~LogMessage()
            {
                if(_logger._fflush_strategy)
                {
                    _logger._fflush_strategy->SyncLog(_loginfo);
                }
            }

            private:
            std::string _curr_time;
            LogLevel _level;
            pid_t _pid;
            std::string _src_name;
            std::string _loginfo;
            int _line_number;
            Logger& _logger;

        };
        LogMessage operator()(LogLevel level,std::string src_name,int line)
        {
            return LogMessage(level,src_name,line,*this);
        }
        ~Logger()
        {

        }
        private:
        std::unique_ptr<LogStrategy> _fflush_strategy;
    };

    Logger logger;
    #define LOG(level) logger(level,__FILE__,__LINE__) //宏定义LOG类型
    #define EnableConsoleLogStrategy logger.EnableConsoleLogStrategy() //宏定义输出控制台策略
    #define EnableFileLogStrategy logger.EnableFileLogStrategy() //宏定义输出文件策略
};
